home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / N8250.C < prev    next >
C/C++ Source or Header  |  1997-05-24  |  22KB  |  963 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * 16550A support plus some statistics added mah@hpuviea.at 15/7/89
  5.  *
  6.  * CTS hardware flow control from dkstevens@ucdavis,
  7.  * additional stats from delaroca@oac.ucla.edu added by karn 4/17/90
  8.  * Feb '91      RLSD line control reorganized by Bill_Simpson@um.cc.umich.edu
  9.  * Sep '91      All control signals reorganized by Bill Simpson
  10.  * Apr '92    Control signals redone again by Phil Karn
  11.  */
  12. #ifdef MSDOS
  13. #include "global.h"
  14. #include <dos.h>
  15. #include "mbuf.h"
  16. #include "proc.h"
  17. #include "iface.h"
  18. #include "n8250.h"
  19. #include "asy.h"
  20. #include "devparam.h"
  21. #include "hardware.h"
  22. #include "kisspoll.h"
  23.  
  24.  
  25. #if !defined(_lint)
  26. static char rcsid[] OPTIONAL = "$Id: n8250.c,v 1.6 1997/05/24 22:13:02 root Exp root $";
  27. #endif
  28.  
  29. #if 0     /* was def TIPMAIL */
  30. #include "cmdparse.h"
  31. extern struct cmds Cmds[];
  32. #endif
  33.  
  34.  
  35. static int get_rlsd_asy (int dev, int new_rlsd);
  36. static void asyrxint (struct asy *asyp, unsigned base);
  37. static void asytxint (struct asy *asyp, unsigned base);
  38. static void asymsint (struct asy *asyp);
  39. static void asycom (struct asy *);
  40. static void asy_monitor (int dev, void *p1, void *p2);
  41. void pasy (struct asy *asyp);
  42.  
  43. struct asy *Asy;    /* allocated in main.c */
  44. static unsigned char fifo_setup;
  45. #ifdef DEBUGASY
  46. static unsigned long ierints = 0;
  47. #endif
  48.  
  49. static void asyint (int dev);
  50. extern int arddec (volatile int *p);
  51.  
  52.  
  53.  
  54. /* Initialize asynch port "dev" */
  55. int
  56. asy_init (
  57. int dev,
  58. struct iface *ifp,
  59. char *arg1,
  60. char *arg2,
  61. int16 bufsize,
  62. int trigchar,
  63. char monitor,
  64. long speed,
  65. int force,
  66. int triglevel,
  67. int polled
  68. )
  69. {
  70. struct fifo *fp;
  71. struct asy *ap;
  72. int chain = 0;
  73. char *ifn;
  74. long interval;
  75. unsigned int base;
  76.  
  77.     ap = &Asy[dev];
  78.     ap->iface = ifp;
  79.     ap->addr = htoi (arg1);
  80.     ap->vec = htoi (arg2);
  81. #ifdef POLLEDKISS
  82.     ap->poller = NULL;
  83. #endif
  84.     ap->chain = chain;
  85.  
  86.     /* Set up receiver FIFO */
  87.     fp = &ap->fifo;
  88.     fp->buf = mallocw (bufsize);
  89.     fp->bufsize = bufsize;
  90.     fp->wp = fp->rp = fp->buf;
  91.     fp->cnt = 0;
  92.     fp->hiwat = 0;
  93.     fp->overrun = 0;
  94.     base = ap->addr;
  95.     ap->trigchar = trigchar;
  96.  
  97.     /* Purge the receive data buffer */
  98.     (void) inportb (base + RBR);
  99.  
  100.     /* Save original mask state, force off interrupts for now */
  101.     if (ap->vec != -1) {
  102.         ap->save.mask = getmask (ap->vec);
  103.         (void) maskoff (ap->vec);
  104.     }
  105.     ap->save.lcr = inportb (base + LCR);
  106.     ap->save.ier = inportb (base + IER);
  107.     ap->save.mcr = inportb (base + MCR);
  108.     ap->msr = ap->save.msr = inportb (base + MSR);
  109.     ap->save.iir = inportb (base + IIR);
  110.  
  111.     /* save speed bytes */
  112.     setbit (base + LCR, LCR_DLAB);
  113.     ap->save.divl = inportb (base + DLL);
  114.     ap->save.divh = inportb (base + DLM);
  115.     clrbit (base + LCR, LCR_DLAB);
  116.  
  117.     /* save some information on the starting state */
  118.     ap->cts_flow_control = (ap->save.msr & MSR_CTS) ? FOUND_UP : FOUND_DOWN;
  119.     ap->rlsd_line_control = (ap->save.msr & MSR_RLSD) ? FOUND_UP : FOUND_DOWN;
  120.     ap->dtr_usage = (ap->save.mcr & MCR_DTR) ? FOUND_UP : FOUND_DOWN;
  121.     ap->rts_usage = (ap->save.mcr & MCR_RTS) ? FOUND_UP : FOUND_DOWN;
  122.  
  123.     /* Set interrupt vector to SIO handler */
  124.     if (ap->vec != -1)    {
  125.         LOCK_FUNCTION(asyint);
  126.         LOCK_VARIABLE(Asy);
  127.         (void) setvect (ap->vec, chain, asyint, dev);
  128.     }
  129.  
  130.     /* Set line control register: 8 bits, no parity */
  131.     outportb (base + LCR, LCR_8BITS);
  132.  
  133.     /* Set the fifo trigger level according to the user's wishes :-) - WG7J */
  134.     if (triglevel == 1)
  135.         fifo_setup = FIFO_SETUP1;
  136.     else if (triglevel == 4)
  137.         fifo_setup = FIFO_SETUP4;
  138.     else if (triglevel == 8)
  139.         fifo_setup = FIFO_SETUP8;
  140.     else if (triglevel == 14)
  141.         fifo_setup = FIFO_SETUP14;
  142.     else
  143.         fifo_setup = FIFO_SETUP4;    /* default to 4 */
  144.  
  145.     /* determine if 16550A, turn on FIFO mode and clear RX and TX FIFOs */
  146.     outportb (base + FCR, FIFO_ENABLE);
  147.  
  148.     /* According to National ap note AN-493, the FIFO in the 16550 chip
  149.      * is broken and must not be used. To determine if this is a 16550A
  150.      * (which has a good FIFO implementation) check that both bits 7
  151.      * and 6 of the IIR are 1 after setting the fifo enable bit. If
  152.      * not, don't try to use the FIFO.
  153.      */
  154.  
  155.     if ((inportb (base + IIR) & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED || force) {
  156.         ap->is_16550a = TRUE;
  157.         outportb (base + FCR, fifo_setup);
  158.     } else {
  159.         /* Chip is not a 16550A. In case it's a 16550 (which has a
  160.          * broken FIFO), turn off the FIFO bit.
  161.          */
  162.         outportb (base + FCR, 0);
  163.         ap->is_16550a = FALSE;
  164.     }
  165.  
  166.     /* Turn on receive interrupts and modem interrupts;
  167.      * leave transmit interrupts off until we actually send data.
  168.      */
  169.     outportb (base + IER, IER_RLS | IER_DAV | IER_MS);
  170.  
  171.     /* Turn on 8250 master interrupt enable (connected to OUT2) */
  172.     setbit (base + MCR, MCR_OUT2);
  173.  
  174.     /* Enable interrupt */
  175.     if (ap->vec != -1)
  176.         (void) maskon (ap->vec);
  177.  
  178.     (void) asy_speed (dev, speed);
  179.  
  180.     if (monitor) {
  181.         /* set up to monitor line signals */
  182.         ap->monitor = newproc (ifn = if_name (ifp, " monitor"),
  183.                   256, asy_monitor, ifp->dev, ifp, NULL, 0);
  184.         free (ifn);
  185.         kwait (NULL);    /* let hooks get set up */
  186.     }
  187.     if ((ap->dtr_usage & FOUND_UP) && (ap->rlsd_line_control & FOUND_UP) || ap->monitor == NULL) {
  188.         if (ifp->iostatus != NULL)
  189.             (void) (*ifp->iostatus) (ifp, PARAM_UP, 0L);
  190.     }
  191. #ifdef POLLEDKISS
  192.     if (polled) {
  193.         /* Calculate the poll interval: some processing time +
  194.          * the packet duration for a mtu size packet.
  195.          */
  196.         interval = (((long) ifp->mtu * 10000L) / speed);
  197.         ap->poller = newproc (ifn = if_name (ifp, " poller"),
  198.            384, kiss_poller, ifp->xdev, (void *) interval, NULL, 0);
  199.         free (ifn);
  200.     }
  201. #endif
  202.     return 0;
  203. }
  204.  
  205.  
  206.  
  207. int
  208. asy_stop (struct iface *ifp)
  209. {
  210. unsigned base;
  211. struct asy *ap;
  212.  
  213.     ap = &Asy[ifp->dev];
  214.  
  215. #ifdef POLLEDKISS
  216.     if (ap->poller)
  217.         killproc (ap->poller);
  218. #endif
  219.     if (ap->monitor != NULL) {
  220.         ap->rlsd_line_control = IGNORED;
  221.         killproc (ap->monitor);
  222.         ap->monitor = NULL;
  223.     }
  224.     if (ap->iface == NULL)
  225.         return -1;    /* Not allocated */
  226.     ap->iface = NULL;
  227.  
  228.     base = ap->addr;
  229.  
  230.     (void) inportb (base + RBR);    /* Purge the receive data buffer */
  231.  
  232.     if (ap->is_16550a) {
  233.         /* Purge hardware FIFOs and disable if we weren't already
  234.          * in FIFO mode when we entered. Apparently some
  235.          * other comm programs can't handle 16550s in
  236.          * FIFO mode; they expect 16450 compatibility mode.
  237.          */
  238.         outportb (base + FCR, fifo_setup);
  239.         if ((ap->save.iir & IIR_FIFO_ENABLED) != IIR_FIFO_ENABLED)
  240.             outportb (base + FCR, 0);
  241.     }
  242.     /* Restore original interrupt vector and 8259 mask state */
  243.     if (ap->vec != -1) {
  244.         (void) freevect (ap->vec);
  245.         (void) maskoff (ap->vec);
  246.     }
  247.     /* Restore speed regs */
  248.     setbit (base + LCR, LCR_DLAB);
  249.     outportb (base + DLL, ap->save.divl);    /* Low byte */
  250.     outportb (base + DLM, ap->save.divh);    /* Hi byte */
  251.     clrbit (base + LCR, LCR_DLAB);
  252.  
  253.     /* Restore control regs */
  254.     outportb (base + LCR, ap->save.lcr);
  255.     outportb (base + IER, ap->save.ier);
  256.     outportb (base + MCR, ap->save.mcr);
  257.  
  258.     if (ap->save.mask)
  259.         (void) maskon (ap->vec);
  260.     else
  261.         (void) maskoff (ap->vec);
  262.  
  263.     free (ap->fifo.buf);
  264.     return 0;
  265. }
  266.  
  267.  
  268.  
  269. /* Set asynch line speed */
  270. int
  271. asy_speed (int dev, int32 bps)
  272. {
  273. unsigned base;
  274. long divisor;
  275. struct asy *asyp;
  276. int i_state;
  277.  
  278.     if (dev >= ASY_MAX)
  279.         return -1;
  280.     asyp = &Asy[dev];
  281.     if (asyp->iface == NULL)
  282.         return -1;
  283.  
  284.     if (bps == 0)
  285.         return -1;
  286.     asyp->speed = bps;
  287.  
  288.     base = asyp->addr;
  289.     divisor = BAUDCLK / bps;
  290.  
  291.     i_state = disable ();
  292.  
  293.     /* Purge the receive data buffer */
  294.     (void) inportb (base + RBR);
  295.     if (asyp->is_16550a)    /* clear tx+rx fifos */
  296.         outportb (base + FCR, FIFO_SETUP);
  297.  
  298.     /* Turn on divisor latch access bit */
  299.     setbit (base + LCR, LCR_DLAB);
  300.  
  301.     /* Load the two bytes of the register */
  302.     outportb (base + DLL, divisor);    /* Low byte */
  303.     outportb (base + DLM, divisor >> 8);    /*lint !e704 * Hi byte */
  304.  
  305.     /* Turn off divisor latch access bit */
  306.     clrbit (base + LCR, LCR_DLAB);
  307.  
  308.     restore (i_state);
  309.     return 0;
  310. }
  311.  
  312.  
  313.  
  314. /* Asynchronous line I/O control */
  315. int32
  316. asy_ioctl (struct iface * ifp, int cmd, int set, int32 val)
  317. {
  318. struct asy *ap = &Asy[ifp->dev];
  319. uint base = ap->addr;
  320.  
  321.     switch (cmd) {
  322.         case PARAM_SPEED:
  323.             if (set)
  324.                 (void) asy_speed (ifp->dev, val);
  325.             return ap->speed;
  326.         case PARAM_DTR:
  327.             if (set) {
  328.                 writebit (base + MCR, MCR_DTR, (int) val);
  329.                 ap->dtr_usage = (val) ? MOVED_UP : MOVED_DOWN;
  330.             }
  331.             return (inportb (base + MCR) & MCR_DTR) ? TRUE : FALSE;
  332.         case PARAM_RTS:
  333.             if (set) {
  334.                 writebit (base + MCR, MCR_RTS, (int) val);
  335.                 ap->rts_usage = (val) ? MOVED_UP : MOVED_DOWN;
  336.             }
  337.             return (inportb (base + MCR) & MCR_RTS) ? TRUE : FALSE;
  338.         case PARAM_DOWN:
  339.             clrbit (base + IER, (char) IER_DAV);
  340.             clrbit (base + MCR, MCR_RTS);
  341.             clrbit (base + MCR, MCR_DTR);
  342.             ap->rts_usage = MOVED_DOWN;
  343.             ap->dtr_usage = MOVED_DOWN;
  344.             return FALSE;
  345.         case PARAM_UP:
  346.             setbit (base + IER, (char) IER_DAV);
  347.             setbit (base + MCR, MCR_RTS);
  348.             setbit (base + MCR, MCR_DTR);
  349.             ap->rts_usage = MOVED_UP;
  350.             ap->dtr_usage = MOVED_UP;
  351.             return TRUE;
  352.         case PARAM_BLIND:
  353.             setbit (base + IER, (char) IER_DAV);
  354.             ap->rlsd_line_control = IGNORED;
  355.  
  356.             if (ap->monitor != NULL) {
  357.                 killproc (ap->monitor);
  358.                 ap->monitor = NULL;
  359.             }
  360.             /* can't see what we are doing, so pretend we're up */
  361.             if (ifp->iostatus != NULL) {
  362.                 (void) (*ifp->iostatus) (ifp, PARAM_UP, 0L);
  363.             }
  364.             return TRUE;
  365.         default:
  366.             return -1;
  367.     }
  368. }
  369.  
  370.  
  371.  
  372. #if 0
  373. /* Open an asynch port for direct I/O, temporarily suspending any
  374.  * packet-mode operations. Returns device number for asy_write and get_asy
  375.  */
  376. int
  377. asy_open (char *name)
  378. {
  379. struct iface *ifp;
  380. int dev;
  381.  
  382.     if ((ifp = if_lookup (name)) == NULL) {
  383.         errno = ENODEV;
  384.         return -1;
  385.     }
  386.     if ((dev = ifp->dev) >= ASY_MAX || Asy[dev].iface != ifp) {
  387.         errno = EINVAL;
  388.         return -1;
  389.     }
  390.     /* Suspend the packet drivers */
  391.     suspend (ifp->rxproc);
  392.     suspend (ifp->txproc);
  393.  
  394.     /* bring the line up (just in case) */
  395.     if (ifp->ioctl != NULL)
  396.         (void) (*ifp->ioctl) (ifp, PARAM_UP, TRUE, 0L);
  397.     return dev;
  398. }
  399.  
  400.  
  401.  
  402. int
  403. asy_close (int dev)
  404. {
  405. struct iface *ifp;
  406.  
  407.     if (dev < 0 || dev >= ASY_MAX) {
  408.         errno = EINVAL;
  409.         return -1;
  410.     }
  411.     /* Resume the packet drivers */
  412.     if ((ifp = Asy[dev].iface) == NULL) {
  413.         errno = EINVAL;
  414.         return -1;
  415.     }
  416.     resume (ifp->rxproc);
  417.     resume (ifp->txproc);
  418.     return 0;
  419. }
  420. #endif
  421.  
  422.  
  423. /* Send a buffer on the serial transmitter and wait for completion */
  424. static int
  425. asy_write (int dev, const void *buf, unsigned short cnt)
  426. {
  427. struct dma *dp;
  428. unsigned base;
  429. struct asy *asyp;
  430. char ier;
  431. int tmp;
  432. int i_state;
  433. struct iface *ifp;
  434.  
  435.     if (dev < 0 || dev >= ASY_MAX)
  436.         return -1;
  437.     asyp = &Asy[dev];
  438.     if ((ifp = asyp->iface) == NULL)
  439.         return -1;
  440.  
  441.     base = asyp->addr;
  442.     dp = &asyp->dma;
  443.  
  444.     if (dp->flags)
  445.         return -1;    /* Already busy */
  446.  
  447.     dp->data = (uint8 *) buf;
  448.     dp->cnt = cnt;
  449.     dp->flags = 1;
  450.  
  451.     /* If CTS flow control is disabled or CTS is true,
  452.      * enable transmit interrupts here so we'll take an immediate
  453.      * interrupt to get things going. Otherwise let the
  454.      * modem control interrupt enable transmit interrupts
  455.      * when CTS comes up. If we do turn on TxE,
  456.      * "kick start" the transmitter interrupt routine, in case just
  457.      * setting the interrupt enable bit doesn't cause an interrupt
  458.      */
  459.  
  460.     if (asyp->cts_flow_control & MOVED_DOWN) {
  461.         /* CTS flow control is enabled; let the modem control
  462.          * interrupt enable transmit interrupts if CTS is off
  463.          */
  464.         ier = IER_MS;
  465.         if (inportb (base + MSR) & MSR_CTS)
  466.             ier |= IER_TxE;
  467.     } else {
  468.         /* Enable transmit interrupts; this will cause an immediate
  469.          * interrupt that will start things going
  470.          */
  471.         ier = IER_TxE;
  472.     }
  473.     setbit (base + IER, ier);
  474.  
  475.     /* Wait for completion */
  476.     for ( ; ; ) {
  477.         i_state = disable ();
  478.         tmp = dp->flags;
  479.         restore (i_state);
  480.         if (tmp == 0)
  481.             break;
  482.         kwait (&asyp->dma);
  483.     }
  484.     ifp->lastsent = secclock ();
  485.     return cnt;
  486. }
  487.  
  488.  
  489.  
  490. /* Blocking read from asynch line
  491.  * Returns character or -1 if aborting
  492.  */
  493. int
  494. get_asy (int dev)
  495. {
  496. struct fifo *fp;
  497. uint8 c;
  498.  
  499.     if (dev < 0 || dev >= ASY_MAX) {
  500.         errno = EINVAL;
  501.         return -1;
  502.     }
  503.  
  504.     fp = &Asy[dev].fifo;
  505.  
  506.     while (fp->cnt == 0)    {
  507.         if (kwait (fp) != 0)
  508.             return -1;
  509.     }        
  510.  
  511.     (void) arddec ((volatile int *)&fp->cnt);
  512.  
  513.     c = *fp->rp++;
  514.     if (fp->rp >= &fp->buf[fp->bufsize])
  515.         fp->rp = fp->buf;
  516.  
  517.     return c;
  518. }
  519.  
  520.  
  521.  
  522. /* Interrupt handler for 8250 asynch chip (called from asyvec.asm) */
  523. static void
  524. asyint (int dev)
  525. {
  526. #ifdef DEBUGASY
  527.     ierints++;
  528. #endif
  529.     asycom (&Asy[dev]);
  530. }
  531.  
  532.  
  533.  
  534. /* Common interrupt handler code for 8250/16550 port */
  535. static void
  536. asycom (struct asy *asyp)
  537. {
  538. unsigned base;
  539. unsigned char iir;
  540.  
  541.     base = asyp->addr;
  542.     while (((iir = inportb (base + IIR)) & IIR_IP) == 0) {
  543.         switch (iir & IIR_ID_MASK) {
  544.             case IIR_RLS:
  545.                 if (inportb (base + LSR) & LSR_OE)
  546.                     asyp->overrun++;
  547.                 break;
  548.             case IIR_RDA:    /* Receiver interrupt */
  549.                 asyrxint (asyp, base);
  550.                 break;
  551.             case IIR_THRE:    /* Transmit interrupt */
  552.                 asytxint (asyp, base);
  553.                 break;
  554.             case IIR_MSTAT:    /* Modem status change */
  555.                 asymsint (asyp);
  556.                 asyp->msint_count++;
  557.                 break;
  558.             default:
  559.                 break;
  560.         }
  561.         /* should happen at end of a single packet */
  562.         if (iir & IIR_FIFO_TIMEOUT)
  563.             asyp->fifotimeouts++;
  564.     }
  565. }
  566.  
  567.  
  568.  
  569. /* Process 8250 receiver interrupts */
  570. static void
  571. asyrxint (struct asy *asyp, unsigned base)
  572. {
  573. struct fifo *fp;
  574. uint8 c, lsr;
  575. int cnt = 0;
  576. int trigseen = FALSE;
  577.  
  578.     asyp->rxints++;
  579.     fp = &asyp->fifo;
  580.  
  581.     for ( ; ; ) {
  582.         lsr = inportb (base + LSR);
  583.         if (lsr & LSR_OE)
  584.             asyp->overrun++;
  585.  
  586.         if (lsr & LSR_DR) {
  587.             asyp->rxchar++;
  588.             c = inportb (base + RBR);
  589.             if (asyp->trigchar == -1 || asyp->trigchar == c)
  590.                 trigseen = TRUE;
  591.             /* If buffer is full, we have no choice but
  592.              * to drop the character
  593.              */
  594.             if (fp->cnt != fp->bufsize) {
  595.                 *fp->wp++ = c;
  596.                 if (fp->wp >= &fp->buf[fp->bufsize])
  597.                     /* Wrap around */
  598.                     fp->wp = fp->buf;
  599.                 fp->cnt++;
  600.                 if (fp->cnt > fp->hiwat)
  601.                     fp->hiwat = fp->cnt;
  602.                 cnt++;
  603.             } else
  604.                 fp->overrun++;
  605.         } else
  606.             break;
  607.     }
  608.     if (cnt > asyp->rxhiwat)
  609.         asyp->rxhiwat = cnt;
  610.     if (trigseen)
  611.         ksignal (fp, 1);
  612. }
  613.  
  614.  
  615.  
  616. /* Handle 8250 transmitter interrupts */
  617. static void
  618. asytxint (struct asy *asyp, unsigned base)
  619. {
  620. struct dma *dp;
  621. int count;
  622. uint8 lsr;
  623.  
  624.     dp = &asyp->dma;
  625.     asyp->txints++;
  626.     if (!dp->flags || !(asyp->msr & MSR_CTS)) {
  627.         /* These events "shouldn't happen". Either the
  628.          * transmitter is idle, in which case the transmit
  629.          * interrupts should have been disabled, or flow control
  630.          * is enabled but CTS is low, and interrupts should also
  631.          * have been disabled.
  632.          */
  633.         clrbit (base + IER, IER_TxE);
  634.         return;        /* Nothing to send */
  635.     }
  636.     lsr = inportb (base + LSR);
  637.     if (lsr & LSR_OE)
  638.         asyp->overrun++;
  639.  
  640.     if ((lsr & LSR_THRE) == 0)
  641.         return;        /* Not really ready */
  642.  
  643.     /* If it's a 16550A, load up to 16 chars into the tx hw fifo
  644.      * at once. With an 8250, it can be one char at most.
  645.      */
  646.     if (asyp->is_16550a) {
  647.         count = (int) min (dp->cnt, OUTPUT_FIFO_SIZE);
  648.  
  649.         /* 16550A: LSR_THRE will drop after the first char loaded
  650.          * so we can't look at this bit to determine if the hw fifo is
  651.          * full. There seems to be no way to determine if the tx fifo
  652.          * is full (any clues?). So we should never get here while the
  653.          * fifo isn't empty yet.
  654.          */
  655.         asyp->txchar += count;
  656.         dp->cnt -= count;
  657.  
  658.         while (count-- != 0)
  659.             outportb (base + THR, *dp->data++);
  660.     } else {        /* 8250 */
  661.         do {
  662.             asyp->txchar++;
  663.             outportb (base + THR, *dp->data++);
  664.         } while (--dp->cnt != 0 && (inportb (base + LSR) & LSR_THRE));
  665.     }
  666.     if (dp->cnt == 0) {
  667.         dp->flags = 0;
  668.         /* Disable further transmit interrupts */
  669.         clrbit (base + IER, IER_TxE);
  670.         ksignal (&asyp->dma, 1);
  671.     }
  672.     return;
  673. }
  674.  
  675.  
  676.  
  677. /* Handle 8250 modem status change interrupt */
  678. static void
  679. asymsint (struct asy *ap)
  680. {
  681. unsigned base = ap->addr;
  682.  
  683.     ap->msr = inportb(base+MSR);
  684.  
  685.     if ( ap->msr & MSR_CTS ) {
  686.         switch ( ap->cts_flow_control ) {
  687.             case FOUND_DOWN:
  688.             case MOVED_DOWN:
  689.                 ap->cts_flow_control = MOVED_UP;
  690.  
  691.                 /* CTS now asserted, enable Transmit interrupts */
  692.                 if(ap->dma.flags)
  693.                     setbit(base+IER,IER_TxE);
  694.                 break;
  695.             default:
  696.                 break;
  697.             
  698.         };
  699.     } else {
  700.         switch ( ap->cts_flow_control ) {
  701.             case FOUND_UP:
  702.             case MOVED_UP:
  703.                 ap->cts_flow_control = MOVED_DOWN;
  704.  
  705.                 /* CTS now dropped, disable Transmit interrupts */
  706.                 clrbit(base+IER,IER_TxE);
  707.                 break;
  708.             default:
  709.                 break;
  710.         };
  711.     }
  712.  
  713.     if ( ap->msr & MSR_RLSD ) {
  714.         switch ( ap->rlsd_line_control ) {
  715.             case FOUND_DOWN:
  716.             case MOVED_DOWN:
  717.                 ap->rlsd_line_control = MOVED_UP;
  718.  
  719.                 /* RLSD just went up */
  720.                 ksignal( &(ap->rlsd_line_control), 1 );
  721.                 break;
  722.             default:
  723.                 break;
  724.         };
  725.     } else {
  726.         switch ( ap->rlsd_line_control ) {
  727.             case FOUND_UP:
  728.             case MOVED_UP:
  729.                 ap->rlsd_line_control = MOVED_DOWN;
  730.  
  731.                 /* RLSD just went down */
  732.                 ksignal( &(ap->rlsd_line_control), 1 );
  733.                 break;
  734.             default:
  735.                 break;
  736.         };
  737.     }
  738.  
  739.     if ( ap->msr & (MSR_TERI | MSR_RI) )
  740.         (void) asy_ioctl( ap->iface, PARAM_UP, TRUE, 0L );
  741. }
  742.  
  743. END_OF_FUNCTION(asyint)
  744.  
  745.  
  746. /* Wait for a signal that the RLSD modem status has changed */
  747. static int
  748. get_rlsd_asy (dev, new_rlsd)
  749. int dev;
  750. int new_rlsd;
  751. {
  752. struct asy *ap = &Asy[dev];
  753.  
  754.     struct iface *ifp = ap->iface;
  755.     int result;
  756.  
  757.     if ( ap->rlsd_line_control & IGNORED )
  758.         return IGNORED;
  759.  
  760.  
  761.     switch ( new_rlsd ) {
  762.         case IGNORED:
  763.             /* Just return the current value */
  764.             return(ap->rlsd_line_control);
  765.  
  766.         case MOVED_DOWN:
  767.             if ( !(ap->rlsd_line_control & FOUND_UP) ) {
  768.                 /* Already at requested value */
  769.                 return(new_rlsd);
  770.             }
  771.             break;
  772.         case MOVED_UP:
  773.             if ( ap->rlsd_line_control & FOUND_UP ) {
  774.                 /* Already at requested value */
  775.                 return(new_rlsd);
  776.             }
  777.             break;
  778.         default:
  779.             break;
  780.     }
  781.  
  782.     /* Wait for state change to requested value */
  783.     while (ap->rlsd_line_control != new_rlsd) {
  784.         kpause(2L);
  785.         kwait( &(ap->rlsd_line_control) );
  786.     }
  787.  
  788.     if ( ap->rlsd_line_control & FOUND_UP )
  789.         result = PARAM_UP;
  790.     else /* DOWN or IGNORED */
  791.         result = PARAM_DOWN;
  792.  
  793.     /* set our control signals to follow RLSD */
  794.     if ( ifp->ioctl != NULL )
  795.         (void) (*ifp->ioctl)( ifp, result, TRUE, 0L );
  796.     if ( ifp->iostatus != NULL )
  797.         (void) (*ifp->iostatus)( ifp, result, 0L );
  798.     return(ap->rlsd_line_control);
  799.  
  800. }
  801.  
  802.  
  803.  
  804. /* Monitor RLSD signal, and report status changes */
  805. static void
  806. asy_monitor (dev, p1, p2)
  807. int dev;
  808. void *p1;
  809. void *p2;
  810. {
  811. int save_rlsd = Asy[dev].rlsd_line_control;
  812.  
  813.     while (save_rlsd != IGNORED) {
  814.         save_rlsd = get_rlsd_asy (dev, (save_rlsd ^ FOUND_UP) | MOVED_DOWN);
  815.         kpause (2);
  816.     }
  817.     Asy[dev].monitor = NULL;
  818. }
  819.  
  820.  
  821.  
  822. /* Poll the asynch input queues; called on every clock tick.
  823.  * This helps limit the interrupt ring buffer occupancy when long
  824.  * packets are being received.
  825.  */
  826. void
  827. asytimer (void)
  828. {
  829. struct asy *asyp;
  830. struct fifo *fp;
  831. int i, i_state;
  832.  
  833.     for (i = 0; i < ASY_MAX; i++) {
  834.         asyp = &Asy[i];
  835.         if (asyp->iface == NULLIF)
  836.             continue;
  837.  
  838.         fp = &asyp->fifo;
  839.         if (fp->cnt != 0)
  840.             ksignal (fp, 1);
  841.         if (asyp->dma.flags && (inportb (asyp->addr + LSR) & LSR_THRE) &&
  842.             (inportb(asyp->addr+IER) & IER_TxE))    {
  843.                 asyp->txto++;
  844.                 i_state = disable ();
  845.                 asytxint (asyp, asyp->addr);
  846.                 restore (i_state);
  847.         }
  848. #if 0 /* was def TIPMAIL */
  849.         if (Tipsuspended[i].ifp)    {
  850.             if (!carrier_detect(i))    {
  851.                 char buf[40];
  852.                 sprintf (buf, "start tip %s %s %d\n", Tipsuspended[i].ifp->name, (Tipsuspended[i].modem) ? "m" : "t", Tipsuspended[i].timeout);
  853.                 cmdparse(Cmds,buf,NULL);
  854.                 Tipsuspended[i].ifp = 0;
  855.                 Tipsuspended[i].modem = 0;
  856.                 Tipsuspended[i].timeout = 0;
  857.             }
  858.         }
  859. #endif
  860.     }
  861. }
  862.  
  863.  
  864.  
  865. void
  866. pasy (struct asy *asyp)
  867. {
  868. #ifdef DEBUGASY
  869. int mcr, ier, iir;
  870. #endif
  871.  
  872.     tprintf ("%s:", asyp->iface->name);
  873.     if (asyp->is_16550a)
  874.         tprintf (" [NS16550A]");
  875.     if (asyp->trigchar != -1)
  876.         tprintf (" [trigger 0x%02x]", asyp->trigchar);
  877.  
  878.     switch (asyp->cts_flow_control) {
  879.         case MOVED_DOWN:
  880.         case MOVED_UP:
  881.             tputs (" [cts flow control]");
  882.             break;
  883.         default:
  884.             break;
  885.     };
  886.     switch (asyp->rlsd_line_control) {
  887.         case MOVED_DOWN:
  888.         case MOVED_UP:
  889.             tputs (" [rlsd line control]");
  890.             break;
  891.         case IGNORED:
  892.             tputs (" [blind]");
  893.             break;
  894.         default:
  895.             break;
  896.     };
  897.  
  898.     tprintf (" %lu bps - bufsize %d\n", asyp->speed, asyp->fifo.bufsize);
  899.  
  900. #ifdef DEBUGASY
  901.     ier = inportb (asyp->addr + IER);
  902.     tprintf (" IE: int %lu  DAV %s  TxE %s  RLS %s  MS %s\n",
  903.         ierints,
  904.         (ier & IER_DAV) ? "On" : "Off",
  905.         (ier & IER_TxE) ? "On" : "Off",
  906.         (ier & IER_RLS) ? "On" : "Off",
  907.         (ier & IER_MS) ? "On" : "Off");
  908.  
  909.     iir = inportb (asyp->addr + IIR);
  910.     tprintf (" IR: int %s  MS %s  THRE %s  RDA %s  RLS %s\n",
  911.         !(iir & IIR_IP) ? "On" : "Off",
  912.         (((iir & IIR_ID_MASK) == IIR_MSTAT) && !(iir & IIR_IP)) ? "On" : "Off",
  913.         ((iir & IIR_ID_MASK) == IIR_THRE) ? "On" : "Off",
  914.         ((iir & IIR_ID_MASK) == IIR_RDA) ? "On" : "Off",
  915.         ((iir & IIR_ID_MASK) == IIR_RLS) ? "On" : "Off");
  916.  
  917.     mcr = inportb (asyp->addr + MCR);
  918.     tprintf (" MC: int %lu  DTR %s  RTS %s  CTS %s  DSR %s  RI %s  CD %s\n",
  919.          asyp->msint_count,
  920.          (mcr & MCR_DTR) ? "On" : "Off",
  921.          (mcr & MCR_RTS) ? "On" : "Off",
  922.          (asyp->msr & MSR_CTS) ? "On" : "Off",
  923.          (asyp->msr & MSR_DSR) ? "On" : "Off",
  924.          (asyp->msr & MSR_RI) ? "On" : "Off",
  925.          (asyp->msr & MSR_RLSD) ? "On" : "Off");
  926.  
  927. #endif
  928.     tprintf (" RX: int %lu  chars %lu  hw over %lu  hw hi %lu\n     ",
  929.          asyp->rxints, asyp->rxchar, asyp->overrun, asyp->rxhiwat);
  930.     asyp->rxhiwat = 0;
  931.     if (asyp->is_16550a)
  932.         tprintf ("fifo TO %lu  ", asyp->fifotimeouts);
  933.     tprintf ("sw over %lu  sw hi %u\n",
  934.          asyp->fifo.overrun, asyp->fifo.hiwat);
  935.     asyp->fifo.hiwat = 0;
  936.  
  937.     tprintf (" TX: int %lu chars %lu THRE TO %lu%s\n",
  938.          asyp->txints, asyp->txchar, asyp->txto,
  939.          asyp->dma.flags ? " BUSY" : "");
  940. }
  941.  
  942.  
  943.  
  944. /* Send a message on the specified serial line */
  945. int
  946. asy_send (dev, bpp)
  947. int dev;
  948. struct mbuf *bpp;
  949. {
  950.     if (dev < 0 || dev >= ASY_MAX)
  951.         return -1;
  952.  
  953.     while (bpp != NULL) {
  954.         /* Send the buffer */
  955.         (void) asy_write (dev, bpp->data, bpp->cnt);
  956.         /* Now do next buffer on chain */
  957.         bpp = free_mbuf (bpp);
  958.     }
  959.     return 0;
  960. }
  961.  
  962. #endif
  963.